#ifndef __PVMCIRCULARBUFFER_H__
#define __PVMCIRCULARBUFFER_H__

#include "pvm/pvmdefs.h"
#include "pvm/pvmtypes.h"

#include "lib/memory/pvmmemory.h"


class PVMCircularBuffer : public PVMAllocableObject
{
public:
	PVMCircularBuffer();
	PVMCircularBuffer(pvm_size size, pvm_bool autoGrow=false);
	~PVMCircularBuffer();
	
	pvm_size getFreeSize();
	pvm_size getUsedSize();

	pvm_size getHeadPosition() {return head;};
	pvm_size getTailPosition() {return tail;};

	//copy data to outout buffer up to maxLength and remove it from internal buffer
	pvm_int fetchData(void* outBuffer, pvm_size maxLength);
	pvm_int fetchByte();//return one byte from buffer or -1 if error

	//copy data to buffer up to maxLength; data stays in internal buffer
	pvm_int readData(void* outBuffer, pvm_size maxLength);
	pvm_int readByte();//return one byte from buffer or -1 if error

	//remove up to sizeToDiscard bytes from internal buffer; returns -1 on error or number of bytes, removed from buffer
	pvm_int discardData(pvm_size sizeToDiscard);

	pvm_int writeData(void* dataPtr, pvm_size len);//return bytes written

	pvm_size getMaxWriteSize();
	//get direct write pointer
	pvm_int8* lockBufferWrite(pvm_size& maxWriteSize);
	//return the number of bytes that was put into the buffer, or -1 on error
	pvm_int unLockBufferWrite(pvm_size sizeWritten);

	//get direct read pointer
	pvm_int8* lockBufferRead(pvm_size& maxReadSize);
	//return the number of bytes that was removed from buffer, or -1 on error
	pvm_int unLockBufferRead(pvm_size sizeToDiscard);
	
	//resize internal buffer
	pvm_int grow(pvm_size bytesToAdd);

	pvm_bool makeEmpty();//discard all data in buffer

	//find first occurrence of byte in buffer (searching is done from head to tail)
	pvm_int findFirstByte(pvm_int8 b);
protected:
	bool allocBuffer(pvm_size size);
	void freeBuffer();
protected:
	enum LockType
	{
		LOCK_NONE = 0,
		LOCK_READ = 1,
		LOCK_WRITE = 2
	};
protected:
	pvm_int8* buffer;
	pvm_size bufferLength;
	pvm_size head;
	pvm_size tail;
	pvm_size bytesInBuffer;
	LockType lockedState;
	pvm_size lastLockSize;
	pvm_bool autoGrow;
};

#endif // __PVMCIRCULARBUFFER_H__
